package juc;

import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

//获取随机数
import static java.util.concurrent.ThreadLocalRandom.current;

/**
 * 试验 CountDownLatch 类
 * 倒计数门闩
 * 
 * @author ben
 * @date 2021-09-12 21:11:14 CST
 */
public class TestCountDownLatch {

	private static Consumer<Object> cs = System.out::println;

	public static void main(String[] args) {
//		test1();
		
		test2();
	}
	
	/**
	 * 试验1：主线程等待2个子线程操作结束再继续操作
	 * 1）latch.countDown() 放到finally中，否则，线程中断会导致主线程挂起；
	 * 2）一个线程中，latch.countDown() 不能执行两次，会造成误判；
	 * 3）奇怪现象：在线程T1执行latch.countDown()两次后，主线程会继续执行，直到结束，但是，整个进程却
	 * 不会结束，会等待 休眠的线程T2执行完毕
	 * @author ben
	 * @date 2021-09-12 21:15:04 CST
	 */
	public static void test1() {
		CountDownLatch latch = new CountDownLatch(2);
		cs.accept("test1() start, latch.count=" + latch.getCount());
		
		// 线程T1
		// 位置1、位置2 的 latch.countDown() 只能存1个，最好保留位置2的
		new Thread(()->{
			final String tname = Thread.currentThread().getName();
			cs.accept(tname + ": start, date=" + new Date());
			
			// 休眠若干秒
			try {
				TimeUnit.SECONDS.sleep(current().nextInt(10));
				// 位置1
//				latch.countDown();
				cs.accept(tname + ": 任务执行结束, latch.count=" + latch.getCount() + ", date=" + new Date());
			} catch (InterruptedException e) {
				cs.accept(tname + ": 任务被中断, date=" + new Date());
			} finally {
				// 位置2
				latch.countDown();
				cs.accept(tname + ": 任务执行结束-finally, latch.count=" + latch.getCount() + ", date=" + new Date());
			}
		}, "T1").start();

		// 线程T2
		// 位置3、位置4 的 latch.countDown() 只能存1个，最好保留位置4的
		new Thread(()->{
			final String tname = Thread.currentThread().getName();
			cs.accept(tname + ": start, date=" + new Date());
			
			// 休眠若干秒
			try {
				TimeUnit.SECONDS.sleep(current().nextInt(20) + 10);
				// 位置3
//				latch.countDown();
				cs.accept(tname + ": 任务执行结束, latch.count=" + latch.getCount() + ", date=" + new Date());
			} catch (InterruptedException e) {
				cs.accept(tname + ": 任务被中断, date=" + new Date());
			} finally {
				// 位置4
				latch.countDown();
				cs.accept(tname + ": 任务执行结束-finally, latch.count=" + latch.getCount() + ", date=" + new Date());
			}
		}, "T2").start();
		
		final String tname = Thread.currentThread().getName();
		try {
			cs.accept(tname + ": call latch.await(), date=" + new Date());
			latch.await();
			cs.accept(tname + ": 子任务执行完毕");
		} catch (InterruptedException e) {
			cs.accept(tname + ": 被中断...latch.count=" + latch.getCount());
			e.printStackTrace();
		}
		
		cs.accept("test1() end, date=" + new Date());
	}

	/**
	 * 试验2：非正常试验
	 * @author ben
	 * @date 2021-09-12 21:53:51 CST
	 */
	public static void test2() {
		cs.accept("test2() start");
		CountDownLatch latch = new CountDownLatch(0);
		// 异常：java.lang.IllegalArgumentException: count < 0
//		CountDownLatch latch = new CountDownLatch(-1);
		cs.accept("1 latch.count=" + latch.getCount());
		
		// 参数为0时执行countDown()
		// 执行成，但是getCount()不变
		latch.countDown();
		latch.countDown();
		latch.countDown();
		latch.countDown();
		latch.countDown();
		cs.accept("2 latch.count=" + latch.getCount());
		
		cs.accept("test2() start");
	}
}
